package com.rj.core.check;

import com.rj.core.constant.CompareType;
import com.rj.core.constant.DigitsEnum;
import com.rj.util.AssertUtils;

import java.util.function.Consumer;
import java.util.function.Function;

public class AssertFiledValue<T, V, R> {

    /**
     * 字段值
     */
    private V value;

    /**
     * order
     * 字段名
     */
    private String title;
    /**
     * 校验对象
     */
    private AssertorBean<T> bean;

    private boolean notEmpty = true;

    private boolean allowEmpty;

    public AssertFiledValue<T, V, R> read(V value, String title, AssertorBean<T> bean, boolean allowEmpty, Integer maxLen) {
        this.value = value;
        this.title = title;
        this.bean = bean;
        this.allowEmpty = allowEmpty;
        if (allowEmpty == false) {
            notEmpty();
        }
        notEmpty = !isEmpty();
        if (notEmpty && maxLen != null) {
            maxLen(maxLen);
        }
        return this;
    }

    public AssertorBean<T> end() {
        return bean;
    }

    public AssertFiledValue<T, V, R> join() {
        return this;
    }

    public AssertFiledValue<T, V, R> notCollection() {
        AssertUtils.notCollection(title, value);
        return this;
    }

    public AssertFiledValue<T, V, R> eq(V leftValue) {
        AssertUtils.eq(allowEmpty, leftValue, value, title);
        return this;
    }

    public AssertFiledValue<T, V, R> compare(V target, CompareType type) {
        AssertUtils.compare(allowEmpty, title, value, target, type);
        return this;
    }

    /**
     * 值在范围内
     *
     * @param minVal
     * @param maxVal
     * @return
     */
    public AssertFiledValue<T, V, R> between(V minVal, V maxVal) {
        return between(minVal, maxVal, CompareType.LE, CompareType.GE);
    }

    /**
     * 值在范围内
     *
     * @param minVal
     * @param maxVal
     * @return
     */
    public AssertFiledValue<T, V, R> between(V minVal, V maxVal, CompareType minType, CompareType maxType) {
        AssertUtils.between(allowEmpty, title, value, minVal, maxVal, minType, maxType);
        return this;
    }

    /**
     * 最大长度
     *
     * @param maxLength
     * @return
     */
    public AssertFiledValue<T, V, R> maxLen(Integer maxLength) {
        return length(null, maxLength);
    }

    /**
     * 最小长度
     *
     * @param minLength
     * @return
     */
    public AssertFiledValue<T, V, R> minLen(Integer minLength) {
        return length(minLength, null);
    }

    /**
     * 字符长度在最大最小范围内
     *
     * @param minLength
     * @param maxLength
     * @return
     */
    public AssertFiledValue<T, V, R> length(Integer minLength, Integer maxLength) {
        AssertUtils.length(allowEmpty, title, (String) value, minLength, maxLength);
        return this;

    }

    /**
     * 长度
     *
     * @param targetLength
     * @return
     */
    public AssertFiledValue<T, V, R> length(Integer targetLength) {
        AssertUtils.length(allowEmpty, title, (String) value, targetLength);
        return this;
    }

    /**
     * 在选择范围
     *
     * @param values
     * @return
     */
    public AssertFiledValue<T, V, R> in(V... values) {
        AssertUtils.in(allowEmpty, title, value, values);
        return this;

    }

    /**
     * 在选择范围
     *
     * @param values
     * @return
     */
    public AssertFiledValue<T, V, R> in(DictList<V> values) {
        AssertUtils.in(allowEmpty, title, value, values, bean);
        return this;

    }

    /**
     * 必须为空
     *
     * @return
     */
    public AssertFiledValue<T, V, R> mustNull() {
        AssertUtils.isTrue(notEmpty, "{}必须为空", this.title);
        return this;
    }

    /**
     * 必须为空
     *
     * @return
     */
    public AssertFiledValue<T, V, R> empty() {
        AssertUtils.isTrue(notEmpty, "{}必须为空", this.title);
        return this;
    }

    /**
     * 不为空
     *
     * @return
     */
    public AssertFiledValue<T, V, R> notEmpty() {
        AssertUtils.isTrue(!notEmpty, "{}不能为空", this.title);
        return this;
    }

    /**
     * 是空值
     *
     * @return
     */
    private boolean isEmpty() {
        return this.value == null || (this.value instanceof String && ((String) this.value).length() == 0);
    }

    /**
     * IF逻辑支持
     *
     * @return
     */
    public AssertFiledValue<T, V, R> ifApply(boolean expression, Function<AssertFiledValue<T, V, R>, AssertFiledValue<T, V, R>> consumer) {
        return expression ? consumer.apply(this) : this;
    }

    /**
     * if else 逻辑处理支持
     *
     * @param expression
     * @param ifApply
     * @param elseApply
     * @return
     */
    public AssertFiledValue<T, V, R> ifElseApply(boolean expression,
                                                 Function<AssertFiledValue<T, V, R>, AssertFiledValue<T, V, R>> ifApply,
                                                 Function<AssertFiledValue<T, V, R>, AssertFiledValue<T, V, R>> elseApply) {
        return expression ? ifApply.apply(this) : elseApply.apply(this);
    }

    /**
     * 整数最大位数
     *
     * @return
     */
    public AssertFiledValue<T, V, R> maxDigits(int integer, int fraction, DigitsEnum type) {
        AssertUtils.maxDigits(allowEmpty, title, value.toString(), integer, fraction, type);
        return this;
    }

    /**
     * @param integer
     * @param fraction
     * @return
     */
    public AssertFiledValue<T, V, R> maxDigits(int integer, int fraction) {
        return maxDigits(integer, fraction, null);
    }

    /**
     * 整数最大位数
     *
     * @return
     */
    public AssertFiledValue<T, V, R> match(String regex, String message, Object... msgParams) {
        AssertUtils.match(allowEmpty, title, value.toString(), regex, message, msgParams);
        return this;
    }

    /**
     * 整数最大位数
     *
     * @return
     */
    public AssertFiledValue<T, V, R> match(String regex) {
        return match(regex, "");
    }

    /**
     * 有效的日期格式
     *
     * @return
     */
    public AssertFiledValue<T, V, R> dateFormat(String[] formats) {
        AssertUtils.dateFormat(allowEmpty, title, (String) value, formats);
        return this;

    }

    /**
     * @return
     */
    public AssertFiledValue<T, V, R> isTrue(boolean expression, Consumer<AssertFiledValue<T, V, R>> consumer
            , String message, Object... msgArgs) {
        AssertUtils.isTrue(expression, message, msgArgs);
        consumer.accept(this);
        return this;
    }

    /**
     * @return
     */
    public AssertFiledValue<T, V, R> isFalse(boolean expression, Consumer<AssertFiledValue<T, V, R>> consumer
            , String message, Object... msgArgs) {
        return isTrue(!expression, consumer, message, msgArgs);
    }
}
